package com.startest.sms.config;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.atomic.AtomicInteger;


/**
 * shiro控制密码输入次数限制5次 超时锁定5分钟
 * UserRealm继承AuthorizingRealm，在其父类AuthenticatingRealm的getAuthenticationInfo方法中会
 *  * 调用credentialsMatcher的 doCredentialsMatch 来验证用户输入用户名密码是否匹配。
 *  此类部队密码加密
 */

public class RetryLimitCredentialsMatcher extends SimpleCredentialsMatcher {

    private static final Logger logger = LoggerFactory.getLogger(RetryLimitCredentialsMatcher.class);

    private int maxRetryNum = 5;
    //利用ehcache、redis记录错误次数
    private Cache<String, AtomicInteger> passworldRetryCache;

    public RetryLimitCredentialsMatcher(CacheManager cacheManager){
        //读取ehcache配置中登录次数限制时间
        passworldRetryCache = cacheManager.getCache("passwordRetryCache");
    }

    public void setMaxRetryNum(int maxRetryNum){
        this.maxRetryNum = maxRetryNum;
    }


    /**
     * 引入Ehcache保存用户登录次数，如果登录失败，retryCount变量会一直累加，如果登录成功，retryCount会从缓存中移除
     * @param token
     * @param info
     * @return
     */
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        System.out.println("进入凭证匹配器");
        //获取用户信息
        String username = (String) token.getPrincipal();
        //从缓存中获取登录次数
        AtomicInteger retryCount = passworldRetryCache.get(username);
        if(retryCount == null){
            //用户没有登录过，登录次数+1并放入缓存
            retryCount = new AtomicInteger(0);
            passworldRetryCache.put(username,retryCount);
        }
        //每次必运行，retryCount自增1
        if(retryCount.incrementAndGet()>maxRetryNum){
            //此处可以做一些逻辑判断，例如锁定用户
            logger.warn("用户:"+username+"在一定时间内尝试登录超过5次");
            throw new ExcessiveAttemptsException("username:"+username+" tried to login more than 5 times in period");
        }
        //登录成功就清楚retryCount次数
        boolean matchs = super.doCredentialsMatch(token,info);
        if(matchs){
            passworldRetryCache.remove(username);
        }
        return matchs;
    }
}
